use std::{rc::Rc, cell::RefCell};

use super::Frame;

// 虚拟机栈
pub struct Stack {
    max_size: usize,
    size: usize,
    top: Option<Rc<RefCell<Frame>>>
}

impl Stack {
    pub fn new_stack(max_size: usize) -> Stack {
        Stack {
            max_size,
            size: 0,
            top: None
        }
    }

    pub fn push(&mut self, frame: Frame) {
        if self.size >= self.max_size {
            panic!("java.lang.StackoverflowError");
        }
        let frame = Rc::new(RefCell::new(frame));
        if self.top.is_some() {
            frame.borrow_mut().set_lower(self.top.take());
        }
        self.top = Some(frame);
        self.size += 1;
    }

    pub fn pop(&mut self) -> Rc<RefCell<Frame>> {
        if self.top.is_none() {
            panic!("jvm stack is empty!")
        }
        let top = self.top.take().unwrap();
        self.top = top.borrow_mut().lower();
        self.size -= 1;
        top
    }

    pub fn top(&self) -> Rc<RefCell<Frame>> {
        if self.top.is_none() {
            panic!("jvm stack is empty!")
        }
        self.top.as_ref().unwrap().clone()
    }

    pub fn is_empty(&self) -> bool {
        self.top.is_none()
    }

    pub fn clear(&mut self) {
        while !self.is_empty() {
            // self.pop()
            let top = self.top.take().unwrap();
            self.top = top.borrow_mut().lower();
            self.size -= 1;
        }
    }

    pub fn get_frames(&self) -> Vec<Rc<RefCell<Frame>>> {
        let mut frames = Vec::with_capacity(self.size);
        let mut frame = self.top.clone();
        while let Some(f) = frame {
            frames.push(f.clone());
            frame = f.borrow().get_lower();
        }
        frames
    }
}
